package com.kalua.list.harvester.tesco;

import static com.kalua.list.harvester.ContentUtil.getContent;
import static com.kalua.list.harvester.HarvesterConstants.DEFAULT_CONNECT_TIMEOUT;

import java.io.IOException;
import java.util.HashMap;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Sets;
import com.kalua.list.domainmodel.NumericId;
import com.kalua.list.domainmodel.TextIdentifier;
import com.kalua.list.domainmodel.product.Product;
import com.kalua.list.domainmodel.product.ProductImpl;
import com.kalua.list.harvester.crawldata.ProductLink;
import com.kalua.list.harvester.parser.AbstractProductParseFunction;
import com.kalua.list.harvester.parser.ProductParseFunction;
import com.kalua.list.harvester.parser.ProductParseResult;

public class TescoParseFunction extends AbstractProductParseFunction {


	private static final Logger logger = LoggerFactory.getLogger(TescoParseFunction.class);
	
	private static final String PRICE_FIELD_KEY = "price";
	private static final String THUMBNAIL_IMAGE_URL_FIELD_KEY = "thumbnailImage";
	private static final String MEDIUM_IMAGE_URL_FIELD_KEY = "mediumImage";
	private static final String PRODUCT_ID_FIELD_KEY = "productId";
	private static final String NAME_FIELD_KEY = "name";

	
	private static final String ESC_JSON_BEGIN_SEQUENCE = "<meta name=\"productdata\" content=\"";
	private static final String ESC_JSON_END_SEQUENCE = "/>";
	private static final String QUOTE_ESCAPE_SEQUENCE = "&quot;";
	
	private TextIdentifier retailerId;
	private int connectTimeout;

	public TescoParseFunction(	TextIdentifier retailerId) 
	{ this(retailerId, DEFAULT_CONNECT_TIMEOUT); }
		
	public TescoParseFunction(	TextIdentifier retailerId,												
												int connectTimeout) {
		this.retailerId = retailerId;
		this.connectTimeout = connectTimeout;
	}
		
	@Override
	public ProductParseResult apply(ProductLink productLink) {
		ProductParseResult result;
		String productId = getProductIdAfterEqualsFromLink(
											productLink.getTargetURL());
		try {
			String content = getContent(productLink.getTargetURL(), 
														this.connectTimeout);
			Set<Product> productSet = 
							parseProductsFromContent(
														content, productLink.getMetaInformation());
			logger.debug("Parsed {} from content {}.", productSet.size(), productLink.getTargetURL());
			result = new ProductParseResult(productId, productSet);
		} catch (IOException exce) {
			logger.error("I/O FAILURE: Unable to download product {}  content from remote site {}.", 
								productId, productLink.getTargetURL());
			result = new ProductParseResult(productId, exce);
		} catch (Throwable exce) {
			logger.error("APP FAILURE: Unexpected error downloading product {} content from remote site.", productId);
			result = new ProductParseResult(productId, exce);			
		}
		return result;
	}

	@Override
	public TextIdentifier getRetailerId() { return this.retailerId; }
	
	@Override
	public ProductParseFunction fromPrototype(NumericId batchId) {
		TescoParseFunction result = 
				new TescoParseFunction(this.retailerId, this.connectTimeout);
		result.setBatchId(batchId);
		return result;
	}
	
	protected Set<Product> parseProductsFromContent(String content,
																					Set<String> classifications) 
																					throws IOException {
		Set<Product> result = Sets.newHashSet();
		int startIndex = content.indexOf(ESC_JSON_BEGIN_SEQUENCE);
		if (startIndex>=0) {			
			int endIndex = content.indexOf(ESC_JSON_END_SEQUENCE, startIndex);			
			String productEncoding = 
					content.substring(startIndex, endIndex);
			productEncoding = 
					productEncoding	.replaceAll(ESC_JSON_BEGIN_SEQUENCE, "")
												.replaceAll(ESC_JSON_END_SEQUENCE, "")
												.replaceAll(QUOTE_ESCAPE_SEQUENCE, "\"");
			ProductImpl product = parseJSONEncoding(productEncoding);
			product.addClassications(classifications);
			result.add(product);						
		}
		
		return result;
	}
	
	private ProductImpl parseJSONEncoding(String productEncoding) throws IOException {
		ProductImpl result;
		@SuppressWarnings("unchecked")
		HashMap<String,Object> jsonMap =
		        new ObjectMapper().readValue(productEncoding, HashMap.class);
		Object jsonName = jsonMap.get(NAME_FIELD_KEY);
		Object jsonRetailerIssuedId = jsonMap.get(PRODUCT_ID_FIELD_KEY);
		Object mediumImage = jsonMap.get(MEDIUM_IMAGE_URL_FIELD_KEY);
		Object thumbnailImage = jsonMap.get(THUMBNAIL_IMAGE_URL_FIELD_KEY);
		Object jsonPrice = jsonMap.get(PRICE_FIELD_KEY);
		double price = jsonPrice!=null ? Double.parseDouble(jsonPrice.toString()) : 0d;
		String name = jsonName != null ? jsonName.toString() : "";
		TextIdentifier retailerIssuedId = 
				new TextIdentifier(jsonRetailerIssuedId!=null ? jsonRetailerIssuedId.toString() : null);
		NumericId productId = 
							createProductId(retailerIssuedId,name);
		result = new ProductImpl(	productId, this.retailerId, getBatchId(),
													retailerIssuedId, 
													name, 
													price, 
													mediumImage!=null ? mediumImage.toString() : null, 
													thumbnailImage!=null ? thumbnailImage.toString() : null);
		result.setBatchLastUpdated(getBatchId());		
		return result;
	}
}